import { RepositoryFactory } from '../database/repositories/index.js';
import { CallLog, UsageStat } from '../database/models/index.js';
import type {
  CallLogAttributes,
  CallLogCreationAttributes,
  UsageStatAttributes,
} from '../database/models/index.js';
import { v4 as uuidv4 } from 'uuid';
import { QueryTypes } from 'sequelize';

interface LogContext {
  sessionId: string;
  userAgent?: string;
  ipAddress?: string;
}

interface CallLogEntry {
  toolName: string;
  inputParams: Record<string, any>;
  outputResult?: Record<string, any>;
  executionTime: number;
  status: 'success' | 'error' | 'timeout';
  errorMessage?: string;
}

interface UsageAnalytics {
  totalCalls: number;
  successRate: number;
  avgExecutionTime: number;
  topTools: Array<{
    toolName: string;
    calls: number;
    successRate: number;
    avgExecutionTime: number;
  }>;
  dailyStats: Array<{
    date: string;
    calls: number;
    successRate: number;
  }>;
  recentErrors: Array<{
    toolName: string;
    errorMessage: string;
    timestamp: Date;
    count: number;
  }>;
}

interface DailyReport {
  date: string;
  summary: {
    totalCalls: number;
    uniqueSessions: number;
    successRate: number;
    avgExecutionTime: number;
  };
  toolBreakdown: Array<{
    toolName: string;
    calls: number;
    successCalls: number;
    errorCalls: number;
    timeoutCalls: number;
    avgExecutionTime: number;
  }>;
  performanceInsights: {
    slowestTool: string;
    fastestTool: string;
    mostUsedTool: string;
    errorProneTools: string[];
  };
}

/**
 * 日志服务 - 负责记录和分析MCP调用日志
 */
export class LoggingService {
  private static instance: LoggingService;
  private repositories?: RepositoryFactory;
  private currentContext?: LogContext;
  private pendingLogs: CallLogEntry[] = [];
  private batchSize = 50;
  private flushInterval = 30000; // 30秒
  private flushTimer?: NodeJS.Timeout;

  constructor(repositories?: RepositoryFactory) {
    this.repositories = repositories;
    this.startAutoFlush();
  }

  /**
   * 获取单例实例
   */
  static getInstance(repositories?: RepositoryFactory): LoggingService {
    if (!LoggingService.instance) {
      LoggingService.instance = new LoggingService(repositories);
    }
    return LoggingService.instance;
  }

  /**
   * 设置当前会话上下文
   */
  setContext(context: Partial<LogContext>): void {
    this.currentContext = {
      sessionId: context.sessionId || uuidv4(),
      userAgent: context.userAgent,
      ipAddress: context.ipAddress,
    };
  }

  /**
   * 生成新的会话ID
   */
  generateSessionId(): string {
    const sessionId = uuidv4();
    this.setContext({ sessionId });
    return sessionId;
  }

  /**
   * 记录工具调用日志
   */
  async logToolCall(entry: CallLogEntry): Promise<void> {
    try {
      if (!this.repositories) {
        // 如果没有数据库连接，只保存到内存
        this.pendingLogs.push(entry);
        this.logToConsole(entry);
        return;
      }

      const logData: CallLogCreationAttributes = {
        session_id: this.currentContext?.sessionId || 'unknown',
        tool_name: entry.toolName,
        input_params: entry.inputParams,
        output_result: entry.outputResult || null,
        execution_time_ms: entry.executionTime,
        status: entry.status,
        error_message: entry.errorMessage || null,
        user_agent: this.currentContext?.userAgent || null,
        ip_address: this.currentContext?.ipAddress || null,
      };

      // 异步写入数据库
      this.pendingLogs.push(entry);
      
      // 如果达到批量大小，立即刷新
      if (this.pendingLogs.length >= this.batchSize) {
        await this.flushLogs();
      }

      // 控制台日志
      this.logToConsole(entry);
      
      // 异步更新统计数据
      this.updateDailyStats(entry).catch(error => {
        console.error('❌ Failed to update daily stats:', error);
      });

    } catch (error) {
      console.error('❌ Failed to log tool call:', error);
    }
  }

  /**
   * 创建性能测量器
   */
  createMeasure(toolName: string, inputParams: Record<string, any>) {
    const startTime = Date.now();
    
    return {
      success: async (outputResult?: Record<string, any>) => {
        const executionTime = Date.now() - startTime;
        await this.logToolCall({
          toolName,
          inputParams,
          outputResult,
          executionTime,
          status: 'success',
        });
      },
      error: async (errorMessage: string) => {
        const executionTime = Date.now() - startTime;
        await this.logToolCall({
          toolName,
          inputParams,
          executionTime,
          status: 'error',
          errorMessage,
        });
      },
      timeout: async () => {
        const executionTime = Date.now() - startTime;
        await this.logToolCall({
          toolName,
          inputParams,
          executionTime,
          status: 'timeout',
        });
      },
    };
  }

  /**
   * 获取使用分析数据
   */
  async getUsageAnalytics(
    timeRange?: {
      from: Date;
      to: Date;
    }
  ): Promise<UsageAnalytics> {
    if (!this.repositories) {
      return this.getLocalAnalytics();
    }

    try {
      const connection = this.repositories.getComponentRepository()['connection'];
      const sequelize = connection.getSequelize();

      // 构建时间范围条件
      let whereClause = '';
      const replacements: any[] = [];
      
      if (timeRange) {
        whereClause = 'WHERE created_at BETWEEN ? AND ?';
        replacements.push(timeRange.from, timeRange.to);
      }

      // 总体统计
      const [totalStats] = await sequelize.query(
        `SELECT 
           COUNT(*) as totalCalls,
           AVG(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as successRate,
           AVG(execution_time_ms) as avgExecutionTime
         FROM call_logs ${whereClause}`,
        { replacements, type: QueryTypes.SELECT }
      ) as any[];

      // 工具排行
      const topTools = await sequelize.query(
        `SELECT 
           tool_name as toolName,
           COUNT(*) as calls,
           AVG(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as successRate,
           AVG(execution_time_ms) as avgExecutionTime
         FROM call_logs ${whereClause}
         GROUP BY tool_name
         ORDER BY calls DESC
         LIMIT 10`,
        { replacements, type: QueryTypes.SELECT }
      ) as any[];

      // 每日统计
      const dailyStats = await sequelize.query(
        `SELECT 
           DATE(created_at) as date,
           COUNT(*) as calls,
           AVG(CASE WHEN status = 'success' THEN 1 ELSE 0 END) as successRate
         FROM call_logs ${whereClause}
         GROUP BY DATE(created_at)
         ORDER BY date DESC
         LIMIT 30`,
        { replacements, type: QueryTypes.SELECT }
      ) as any[];

      // 最近错误
      const recentErrors = await sequelize.query(
        `SELECT 
           tool_name as toolName,
           error_message as errorMessage,
           MAX(created_at) as timestamp,
           COUNT(*) as count
         FROM call_logs 
         WHERE status = 'error' AND error_message IS NOT NULL ${timeRange ? 'AND created_at BETWEEN ? AND ?' : ''}
         GROUP BY tool_name, error_message
         ORDER BY timestamp DESC
         LIMIT 20`,
        { replacements: timeRange ? replacements : [], type: QueryTypes.SELECT }
      ) as any[];

      return {
        totalCalls: parseInt(totalStats?.totalCalls || '0'),
        successRate: parseFloat(totalStats?.successRate || '0'),
        avgExecutionTime: parseFloat(totalStats?.avgExecutionTime || '0'),
        topTools: topTools.map((tool: any) => ({
          toolName: tool.toolName,
          calls: parseInt(tool.calls),
          successRate: parseFloat(tool.successRate),
          avgExecutionTime: parseFloat(tool.avgExecutionTime),
        })),
        dailyStats: dailyStats.map((stat: any) => ({
          date: stat.date,
          calls: parseInt(stat.calls),
          successRate: parseFloat(stat.successRate),
        })),
        recentErrors: recentErrors.map((error: any) => ({
          toolName: error.toolName,
          errorMessage: error.errorMessage,
          timestamp: new Date(error.timestamp),
          count: parseInt(error.count),
        })),
      };

    } catch (error) {
      console.error('❌ Failed to get usage analytics:', error);
      return this.getLocalAnalytics();
    }
  }

  /**
   * 获取每日报告
   */
  async getDailyReport(date?: string): Promise<DailyReport> {
    const targetDate = date ?? new Date().toISOString().split('T')[0];
    
    if (!this.repositories) {
      return this.generateEmptyReport(targetDate);
    }

    try {
      const usageStats = await UsageStat.findAll({
        where: { date: targetDate },
        order: [['total_calls', 'DESC']],
      });

      if (usageStats.length === 0) {
        return this.generateEmptyReport(targetDate);
      }

      const summary = usageStats.reduce(
        (acc, stat) => ({
          totalCalls: acc.totalCalls + stat.total_calls,
          uniqueSessions: acc.uniqueSessions + stat.unique_sessions,
          successRate: acc.successRate + (stat.success_calls / stat.total_calls) * stat.total_calls,
          avgExecutionTime: acc.avgExecutionTime + stat.avg_execution_time_ms * stat.total_calls,
        }),
        { totalCalls: 0, uniqueSessions: 0, successRate: 0, avgExecutionTime: 0 }
      );

      summary.successRate = summary.successRate / summary.totalCalls;
      summary.avgExecutionTime = summary.avgExecutionTime / summary.totalCalls;

      const toolBreakdown = usageStats.map(stat => ({
        toolName: stat.tool_name,
        calls: stat.total_calls,
        successCalls: stat.success_calls,
        errorCalls: stat.error_calls,
        timeoutCalls: stat.timeout_calls,
        avgExecutionTime: stat.avg_execution_time_ms,
      }));

      // 性能洞察
      const sortedByTime = [...usageStats].sort((a, b) => b.avg_execution_time_ms - a.avg_execution_time_ms);
      const sortedByCalls = [...usageStats].sort((a, b) => b.total_calls - a.total_calls);
      const errorProneTools = usageStats
        .filter(stat => stat.error_calls / stat.total_calls > 0.1)
        .map(stat => stat.tool_name);

      return {
        date: (targetDate || new Date().toISOString().split('T')[0]) as string,
        summary: {
          totalCalls: summary.totalCalls,
          uniqueSessions: Math.max(...usageStats.map(s => s.unique_sessions)),
          successRate: Math.round(summary.successRate * 100) / 100,
          avgExecutionTime: Math.round(summary.avgExecutionTime * 100) / 100,
        },
        toolBreakdown,
        performanceInsights: {
          slowestTool: sortedByTime[0]?.tool_name || 'N/A',
          fastestTool: sortedByTime[sortedByTime.length - 1]?.tool_name || 'N/A',
          mostUsedTool: sortedByCalls[0]?.tool_name || 'N/A',
          errorProneTools,
        },
      };

    } catch (error) {
      console.error('❌ Failed to get daily report:', error);
      return this.generateEmptyReport(targetDate);
    }
  }

  /**
   * 获取最近的调用日志
   */
  async getRecentLogs(
    limit: number = 50,
    toolName?: string
  ): Promise<CallLogAttributes[]> {
    if (!this.repositories) {
      return [];
    }

    try {
      const whereClause: any = {};
      if (toolName) {
        whereClause.tool_name = toolName;
      }

      const logs = await CallLog.findAll({
        where: whereClause,
        order: [['created_at', 'DESC']],
        limit,
      });

      return logs.map(log => log.toJSON());

    } catch (error) {
      console.error('❌ Failed to get recent logs:', error);
      return [];
    }
  }

  /**
   * 批量刷新日志到数据库
   */
  private async flushLogs(): Promise<void> {
    if (!this.repositories || this.pendingLogs.length === 0) {
      return;
    }

    try {
      const logData = this.pendingLogs.map(entry => ({
        session_id: this.currentContext?.sessionId || 'unknown',
        tool_name: entry.toolName,
        input_params: entry.inputParams,
        output_result: entry.outputResult || null,
        execution_time_ms: entry.executionTime,
        status: entry.status,
        error_message: entry.errorMessage || null,
        user_agent: this.currentContext?.userAgent || null,
        ip_address: this.currentContext?.ipAddress || null,
      }));

      await CallLog.bulkCreate(logData);
      
      console.log(`📝 Flushed ${this.pendingLogs.length} log entries to database`);
      this.pendingLogs = [];

    } catch (error) {
      console.error('❌ Failed to flush logs to database:', error);
    }
  }

  /**
   * 更新每日统计数据
   */
  private async updateDailyStats(entry: CallLogEntry): Promise<void> {
    if (!this.repositories) {
      return;
    }

    try {
      const today = new Date().toISOString().split('T')[0];
      
      // 直接使用 findOrCreate，忽略并发错误
      const [stat, created] = await UsageStat.findOrCreate({
        where: {
          date: today,
          tool_name: entry.toolName,
        },
        defaults: {
          date: today as string,
          tool_name: entry.toolName,
          total_calls: 1,
          success_calls: entry.status === 'success' ? 1 : 0,
          error_calls: entry.status === 'error' ? 1 : 0,
          timeout_calls: entry.status === 'timeout' ? 1 : 0,
          avg_execution_time_ms: entry.executionTime,
          max_execution_time_ms: entry.executionTime,
          min_execution_time_ms: entry.executionTime,
          unique_sessions: 1,
        },
      });

      if (!created) {
        // 更新现有统计
        const newTotalCalls = stat.total_calls + 1;
        const newAvgTime = (stat.avg_execution_time_ms * stat.total_calls + entry.executionTime) / newTotalCalls;

        await stat.update({
          total_calls: newTotalCalls,
          success_calls: stat.success_calls + (entry.status === 'success' ? 1 : 0),
          error_calls: stat.error_calls + (entry.status === 'error' ? 1 : 0),
          timeout_calls: stat.timeout_calls + (entry.status === 'timeout' ? 1 : 0),
          avg_execution_time_ms: newAvgTime,
          max_execution_time_ms: Math.max(stat.max_execution_time_ms, entry.executionTime),
          min_execution_time_ms: Math.min(stat.min_execution_time_ms, entry.executionTime),
        });
      }

    } catch (error: unknown) {
      // 忽略并发约束错误，因为其他请求可能已经处理了这个统计
      if (error instanceof Error && error.name !== 'SequelizeUniqueConstraintError') {
        console.error('❌ Failed to update daily stats:', error);
      }
    }
  }

  /**
   * 控制台日志输出
   */
  private logToConsole(entry: CallLogEntry): void {
    const status = entry.status === 'success' ? '✅' : entry.status === 'error' ? '❌' : '⏰';
    const timeColor = entry.executionTime > 1000 ? '🐌' : entry.executionTime > 500 ? '⚠️' : '⚡';
    
    console.log(`${status} ${timeColor} [${entry.toolName}] ${entry.executionTime}ms`);
    
    if (entry.status === 'error' && entry.errorMessage) {
      console.error(`   Error: ${entry.errorMessage}`);
    }
  }

  /**
   * 获取本地分析数据（内存模式）
   */
  private getLocalAnalytics(): UsageAnalytics {
    const totalCalls = this.pendingLogs.length;
    const successCalls = this.pendingLogs.filter(log => log.status === 'success').length;
    const avgTime = this.pendingLogs.reduce((sum, log) => sum + log.executionTime, 0) / totalCalls || 0;

    const toolCounts = this.pendingLogs.reduce((acc, log) => {
      acc[log.toolName] = (acc[log.toolName] || 0) + 1;
      return acc;
    }, {} as Record<string, number>);

    const topTools = Object.entries(toolCounts)
      .map(([toolName, calls]) => ({
        toolName,
        calls,
        successRate: 1,
        avgExecutionTime: avgTime,
      }))
      .sort((a, b) => b.calls - a.calls)
      .slice(0, 5);

    return {
      totalCalls,
      successRate: successCalls / totalCalls || 0,
      avgExecutionTime: avgTime,
      topTools,
      dailyStats: [],
      recentErrors: [],
    };
  }

  /**
   * 生成空报告
   */
  private generateEmptyReport(date: string | undefined): DailyReport {
    const reportDate = date || new Date().toISOString().split('T')[0];
    return {
      date: reportDate as string,
      summary: {
        totalCalls: 0,
        uniqueSessions: 0,
        successRate: 0,
        avgExecutionTime: 0,
      },
      toolBreakdown: [],
      performanceInsights: {
        slowestTool: 'N/A',
        fastestTool: 'N/A',
        mostUsedTool: 'N/A',
        errorProneTools: [],
      },
    };
  }

  /**
   * 开始自动刷新
   */
  private startAutoFlush(): void {
    this.flushTimer = setInterval(() => {
      this.flushLogs().catch(error => {
        console.error('❌ Auto flush failed:', error);
      });
    }, this.flushInterval);
  }

  /**
   * 清理资源
   */
  cleanup(): void {
    if (this.flushTimer) {
      clearInterval(this.flushTimer);
      this.flushTimer = undefined;
    }
    
    // 最后一次刷新
    this.flushLogs().catch(console.error);
  }
}